home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 001 / colorful / colorful.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  19KB  |  490 lines

  1. /*
  2.  * Article 582 of net.micro.amiga:
  3.  * ion: version B 2.10.2 9/17/84 chuqui version 1.9 3/12/85; site unisoft.UUCP
  4.  * Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site amiga.amiga.UUCP
  5.  * Path: unisoft!dual!vecpyr!lll-lcc!lll-crg!seismo!hao!hplabs!pesnta!greipa!decwrl!pyramid!amiga!bobp
  6.  * From: bobp@amiga.UUCP (Robert S. Pariseau)
  7.  * Newsgroups: net.micro.amiga
  8.  * Subject: More Fun with 6 Planes (LONG SOURCE)
  9.  * Message-ID: <223@amiga.amiga.UUCP>
  10.  * Date: 11 Nov 85 10:39:27 GMT
  11.  * Date-Received: 14 Nov 85 21:00:59 GMT
  12.  * Reply-To: bobp@snake.UUCP (Robert S. Pariseau)
  13.  * Organization: Commodore-Amiga Inc., 983 University Ave #D, Los Gatos CA 95030
  14.  * Lines: 471
  15.  * 
  16.  * TITLE:  More Fun with 6 Planes (LONG SOURCE)
  17.  * 
  18.  * The source below is a bit of eye-candy that shows off the use of Hold
  19.  * and Modify graphics display mode on the Amiga.  Hold and Modify (or HAM
  20.  * for short) is a compromise between the limited direct color access of
  21.  * an inexpensive color-palette, frame buffer graphics engine like the
  22.  * Amiga, and the high cost of a direct reading frame buffer graphic engine
  23.  * like some of the more expensive CAD systems.  On the Amiga, the bits
  24.  * associated with a given pixel select one of the 32 color registers.  Each
  25.  * color register contains a color value consisting of 4 bits of Red
  26.  * component, 4 bits of Green, and 4 bits of Blue -- yielding 4096 different
  27.  * colors from black to white.  The Amiga hardware has sufficient bandwidth
  28.  * to retrieve 6 bit-planes worth of data for a given pixel (4 in high
  29.  * resolution display).  The combination of these two constraints says that
  30.  * in a static display (no dynamic color changing going on in the 
  31.  * background), you can display up to 32 colors simultaneously in low
  32.  * res and up to 16 colors simultaneously in highs res choosen out of
  33.  * the palette of 4096 possible colors.
  34.  * 
  35.  * [Note: as discussed earlier, you can actually get up to 64 distinct
  36.  * colors in low res using 6 planes and EXTRA_HALFBRITE display mode.
  37.  * Further, note that dynamic color changing goes on all the time in
  38.  * normal Amiga displays -- that's how each of the separately slideable
  39.  * screens gets its own color palette for instance.]
  40.  * 
  41.  * If the Amiga were only somehow capable of pulling in 12 planes of data
  42.  * per pixel, then we could avoid using the color palette altogether.  We
  43.  * could encode the desired pixel color (4 bits each R, G, and B) directly
  44.  * into the frame buffer.  This would allow us to independently choose
  45.  * any of the 4096 colors for each pixel -- with no limit on how many
  46.  * different colors appeared in a given display.
  47.  * 
  48.  * [Note: there's a downside to this as well.  Since the display doesn't
  49.  * feed through a color palette, there's no easy way of swapping or
  50.  * changing colors in your picture -- you have to actually go out and
  51.  * change all those pixels.  With a color palette, you just change the
  52.  * color values in the registers.  This trick is fundamental to the
  53.  * technique of "color cycle animation".]
  54.  * 
  55.  * HAM is a color modulation technique which approaches the flexibility
  56.  * of a direct reading frame buffer.  Using HAM, you can specify any
  57.  * desired color out of the 4096 available within 3 horizontally
  58.  * adjacent pixels.  Here is how it works.
  59.  * 
  60.  * Consider a 4 plane image.  The 4 bits of each pixel select one of the
  61.  * first 16 color registers.  Now consider the extra 2 bits per pixel
  62.  * of a 6 plane HAM image.  Those extra 2 bits are used as control bits,
  63.  * selecting between the following 4 choices:
  64.  * 
  65.  * 0) Use the lower 4 bits as a color register selector, just as normal.
  66.  * 
  67.  * 1) Use the lower 4 bits as the Blue component of the color for this
  68.  *    pixel.  Copy the Red and Green components of the color for this
  69.  *    pixel from the color of the Playfield pixel immediately to the
  70.  *    left of this one.
  71.  * 
  72.  * 2) Use the lower 4 bits as the Red component of the color for this
  73.  *    pixel.  Copy the Blue and Green components of the color for this
  74.  *    pixel from the color of the Playfield pixel immediately to the
  75.  *    left of this one.
  76.  * 
  77.  * 3) Use the lower 4 bits as the Green component of the color for this
  78.  *    pixel.  Copy the Red and Blue components of the color for this
  79.  *    pixel from the color of the Playfield pixel immediately to the
  80.  *    left of this one.
  81.  * 
  82.  * Note that only the color produced for the pixel is varied.  The contents
  83.  * of the color registers themselves are NOT changed by HAM.  Also note
  84.  * that the effects are cumulative.  Thus, in 3 adjacent pixels, you can
  85.  * Modify-Red, Modify-Green, and Modify-Blue, thereby producing any color
  86.  * you want.
  87.  * 
  88.  * Finally, note that a Modify-x pixel takes its "Hold" colors from the
  89.  * color that is OR WOULD HAVE BEEN produced for the PLAYFIELD (i.e.,
  90.  * frame buffer) pixel immediately to its left.  This means that sprite
  91.  * images moving over the display do NOT mess up your carefully choosen
  92.  * HAM colors.
  93.  * 
  94.  * There is a hardware mode bit that controls HAM.  A HAM display requires
  95.  * 5 or 6 bit planes.  If you provide a 5 plane image, the hardware assumes
  96.  * a 6th bit value of 0 for each pixel -- this means you can only choose
  97.  * normal and Modify-Blue out of the choices above.
  98.  * 
  99.  * The graphics kernel software automatically supports HAM as a ViewPort
  100.  * attribute.  That means that each of your separately slideable ViewPorts
  101.  * (Screens in Intuition lingo) can have, or not have, HAM turned on without
  102.  * affecting the others.
  103.  * 
  104.  * BEWARE!  Some of the older developer machines and store demo machines
  105.  * do not produce reliable HAM images.  ALL of the consumer machines do
  106.  * HAM just fine.
  107.  */
  108.  
  109. /*
  110.  * ----------------------------Program Notes:
  111.  * 
  112.  * The Colorful program will compile and link cleanly using the native
  113.  * Amiga Lattice C tools on the standard V1.0 C disk.  The Make script
  114.  * in the examples directory will do all the work for you.  As usual,
  115.  * I recommend that you copy the source into ram: disk and then direct
  116.  * Make at it by typing:
  117.  * 
  118.  *   1> execute Make ram:Colorful
  119.  * 
  120.  * The program displays 256 boxes each having a different color out of
  121.  * the possible 4096.  Colorful listens for left mouse button events
  122.  * and switches between two display modes.  The first is an ordered
  123.  * display with labelled color components.  The second is a random
  124.  * display where boxes randomly selected have their color randomly
  125.  * changed.  Note that at no time do any 2 boxes share the same color.
  126.  * 
  127.  * If you are sharp-eyed, you will notice a narrow stripe of red and a
  128.  * narrow stripe of green at the leading (leftmost) edge of each of the
  129.  * boxes.  These are the color modifiers in action.  Each box consists
  130.  * of a vertical line of Modify-Red, followed by a vertical line of
  131.  * Modify-Green, followed by a rectangle of Modify-Blue as follows:
  132.  * 
  133.  *      RGBBBBBBBBB
  134.  *      RGBBBBBBBBB
  135.  *      RGBBBBBBBBB
  136.  *      RGBBBBBBBBB
  137.  *      RGBBBBBBBBB
  138.  *      RGBBBBBBBBB
  139.  * 
  140.  * The routine hamBox() produces such a box.
  141.  * 
  142.  * For further information, see the Amiga Hardware Manual, the Amiga
  143.  * ROM Kernel Manual, and the manual Intuition:  The Amiga User Interface.
  144.  * 
  145.  * ----------------------------Program Source Follows:
  146.  * 
  147.  */
  148.  
  149. /***********************************************************************
  150.  *  Colorful -- A demo of the Amiga's Hold and Modify mode, showing, at
  151.  *              all times,  a different subset of 256 of the 4096
  152.  *              colors available on the Amiga.  At any moment, no two
  153.  *              squares have the same exact color in them.
  154.  *
  155.  *  Rob Peck     -- November  5, 1985
  156.  *  Bob Pariseau -- November 10, 1985   (Rework for tutorial)
  157.  *
  158.  **********************************************************************/
  159.  
  160. #include <exec/types.h>
  161. #include <exec/tasks.h>
  162. #include <exec/libraries.h>
  163. #include <exec/devices.h>
  164. #include <devices/keymap.h>
  165. #include <graphics/copper.h>
  166. #include <graphics/display.h>
  167. #include <graphics/gfxbase.h>
  168. #include <graphics/text.h>
  169. #include <graphics/view.h>
  170. #include <graphics/gels.h>
  171. #include <graphics/regions.h>
  172. #include <hardware/blit.h>
  173. #include <intuition/intuition.h>
  174. #include <intuition/intuitionbase.h>
  175.  
  176. #define  XSIZE 11                      /* Color box sizes             */
  177. #define  YSIZE 6
  178.  
  179. struct   GfxBase       *GfxBase;       /* Export the library pointers */
  180. struct   IntuitionBase *IntuitionBase;
  181.  
  182.  
  183. struct   RastPort      *rp;            /* Graphics structures           */
  184. struct   ViewPort      *vp;
  185.  
  186. struct TextAttr TestFont =
  187.     {
  188.        "topaz.font", /* Standard system font */
  189.        8,    0,    0
  190.     };
  191.  
  192. struct   Window        *w;             /* Intuition structures        */ 
  193. struct   Screen        *screen;
  194. struct   IntuiMessage  *message;
  195.  
  196.  
  197. struct NewScreen ns = {
  198.    0, 0,                               /* start position                */
  199.    320, 200, 6,                        /* width, height, depth          */
  200.    0, 1,                               /* detail pen, block pen         */
  201.    HAM,                                /* Hold and Modify ViewMode      */
  202.    CUSTOMSCREEN,                       /* screen type                   */
  203.    &TestFont,                          /* font to use                   */
  204.    " 256 different out of 4096",       /* default title for screen      */
  205.    NULL                                /* pointer to additional gadgets */
  206.    };
  207.  
  208.  
  209. struct NewWindow nw = {
  210.         0, 11,                         /* start position                */
  211.         320, 186,                      /* width, height                 */
  212.         -1, -1,                        /* detail pen, block pen         */
  213.         MOUSEBUTTONS|CLOSEWINDOW,      /* IDCMP flags                   */
  214.         ACTIVATE|WINDOWCLOSE,          /* window flags                  */
  215.         NULL,                          /* pointer to first user gadget  */
  216.         NULL,                          /* pointer to user checkmark     */
  217.         "colors at any given moment",  /*  window title                 */
  218.         NULL,                          /* pointer to screen (set below) */
  219.         NULL,                          /* pointer to superbitmap        */
  220.         0, 0, 320, 186,                /* ignored since not sizeable    */
  221.         CUSTOMSCREEN                   /* type of screen desired        */
  222.         };
  223.  
  224.  
  225.  
  226. LONG  squarecolor[16 * 16], freecolors[4096-(16*16)];
  227. SHORT squares[16 * 16];
  228. SHORT xpos[16], ypos[16];
  229.  
  230. char  *number[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
  231.                     "A", "B", "C", "D", "E", "F" };
  232.  
  233. SHORT sStop, cStop, sequence;
  234. BOOL  textneeded;
  235.  
  236.  
  237.  
  238. main()
  239. {
  240.    ULONG  class;
  241.    USHORT code, i;
  242.    BOOL   wheelmode;
  243.  
  244.    for(i=0; i<16; i++)               /* Establish color square positions */
  245.       {
  246.       xpos[i] = (XSIZE + 4) * i + 20;
  247.       ypos[i] = (YSIZE + 3) * i + 21;
  248.       }
  249.  
  250.    GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
  251.    if (GfxBase == NULL) exit();
  252.  
  253.    IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
  254.    if (IntuitionBase == NULL)
  255.    {
  256.       CloseLibrary(GfxBase);
  257.       exit();
  258.    }
  259.  
  260.    screen = (struct Screen *)OpenScreen(&ns); 
  261.    if (screen == NULL)
  262.    {
  263.       CloseLibrary(IntuitionBase);
  264.       CloseLibrary(GfxBase);
  265.       exit();
  266.    }
  267.  
  268.    nw.Screen = screen;                /* Open window in our new screen */
  269.    w = (struct Window *)OpenWindow(&nw);
  270.    if (w == NULL)
  271.    {
  272.       CloseScreen(screen);
  273.       CloseLibrary(IntuitionBase);
  274.       CloseLibrary(GfxBase);
  275.       exit();
  276.    }
  277.  
  278.    vp = &screen->ViewPort;             /* Set colors in screen's VP    */
  279.    rp = w->RPort;                      /* Render into the window's RP  */
  280.  
  281.    /*  Set the color registers:  Black, Red, Green, Blue, White */
  282.  
  283.    SetRGB4(vp, 0, 00, 00, 00);   
  284.    SetRGB4(vp, 1, 15, 00, 00);    
  285.    SetRGB4(vp, 2, 00, 15, 00);   
  286.    SetRGB4(vp, 3, 00, 00, 15);
  287.    SetRGB4(vp, 4, 15, 15, 15);
  288.  
  289.    SetBPen(rp, 0);                    /* Insure clean text              */
  290.    textneeded = TRUE;
  291.    wheelmode  = TRUE;                 /* Start with Color Wheel display */
  292.  
  293.    FOREVER
  294.    {  /* Process any and all messages in the queue, then update the     */
  295.       /* display colors once, then come back here to look at the queue  */
  296.       /* again.  If you see a left-mouse-button-down event, then switch */
  297.       /* display modes.  If you see a Close-Window-gadget event, then   */
  298.       /* clean up and exit the program.  NOTE:  This is a BUSY LOOP so  */
  299.       /* that the colors will cycle as quickly as possible.             */
  300.  
  301.       while((message = (struct IntuiMessage *)GetMsg(w->UserPort)) != NULL)
  302.       {
  303.          class = message->Class;
  304.          code  = message->Code;
  305.          ReplyMsg(message);       /* Can't reply until done using it!   */
  306.  
  307.          if(class == CLOSEWINDOW)                   /* Exit the program */
  308.          {
  309.             CloseWindow(w);
  310.             CloseScreen(screen);
  311.             CloseLibrary(IntuitionBase);
  312.             CloseLibrary(GfxBase);
  313.             exit();
  314.          };
  315.  
  316.          if(class == MOUSEBUTTONS && code == SELECTDOWN)  /* swap modes */
  317.          {
  318.             wheelmode = NOT wheelmode;
  319.  
  320.             SetAPen(rp, 0);                   /* Clear the drawing area */
  321.             SetDrMd(rp, JAM1);
  322.             RectFill(rp, 3, 12, 318, 183);
  323.             textneeded = TRUE; 
  324.          }
  325.       }
  326.       if(wheelmode) colorWheel();  else colorFull();
  327.    }
  328. }
  329.  
  330.  
  331. colorFull()              /* Display a ramdomized set of colors          */
  332. {
  333.    SHORT sChoice, cChoice, usesquare;
  334.    LONG  usecolor;
  335.  
  336.    if(textneeded)        /* First call since mode change?               */
  337.    {
  338.        prompt();
  339.        sStop = 255;        /* Top of list of squares yet to change      */
  340.        cStop = 4095 - 256; /* Top of list of colors still needing use   */
  341.  
  342.        for(usecolor=0; usecolor<256; usecolor++)   /* Initialize colors */
  343.        {
  344.           usesquare = usecolor;
  345.           squares[usesquare] = usesquare;
  346.           squarecolor[usesquare] = usecolor;
  347.           hamBox(usecolor, xpos[usesquare % 16], ypos[usesquare / 16]);
  348.        }
  349.  
  350.        for(usecolor=256; usecolor<4095; usecolor++) /* Ones not yet used */
  351.           freecolors[usecolor - 256] = usecolor;
  352.    }
  353.  
  354. /*************************************************************************
  355.  * Randomly choose next square to change such that all squares change
  356.  * color at least once before any square changes twice.  squares[0]
  357.  * through squares[sStop] are the square numbers that have not yet
  358.  * changed in this pass.  RangeRand(r) is an integer function provided
  359.  * in "amiga.lib" which produces a random result in the range 0 to
  360.  * (r-1) given an integer r in the range 1 to 65535.
  361.  ************************************************************************/
  362.  
  363.    sChoice = RangeRand(sStop + 1);        /* Pick a remaining square    */
  364.  
  365.    usesquare = squares[sChoice];          /* Extract square number      */
  366.    squares[sChoice] = squares[sStop];     /* Swap it with sStop slot    */
  367.    squares[sStop] = usesquare;
  368.  
  369.    if(NOT sStop--) sStop = 255;           /* Only one change per pass   */
  370.  
  371. /************************************************************************
  372.  * Randomly choose new color for selected square such that all colors
  373.  * are used once before any color is used again, and such that no two
  374.  * squares simultaneously have the same color.  freecolors[0] through
  375.  * freecolors[cStop] are the colors that have not yet been choosen in
  376.  * this pass.  Note that the 256 colors in use at the end of the
  377.  * previous pass are not available for choice in this pass.
  378.  ***********************************************************************/
  379.  
  380.    cChoice = RangeRand(cStop + 1);
  381.  
  382.    usecolor = freecolors[cChoice];
  383.    freecolors[cChoice] = freecolors[cStop];
  384.    freecolors[cStop] = squarecolor[usesquare];
  385.    squarecolor[usesquare] = usecolor;
  386.  
  387.    if(NOT cStop--) cStop = 4095 - 256;
  388.       
  389.  
  390.    hamBox(usecolor, xpos[usesquare % 16], ypos[usesquare / 16]);
  391. }
  392.  
  393.  
  394. colorWheel()                  /* Display an ordered set of colors */
  395. {
  396.    SHORT  i, j;
  397.  
  398.    if(textneeded)
  399.    {
  400.       prompt();
  401.  
  402.       SetAPen(rp, 2);              /* Green pen for green color numbers */
  403.       Move(rp, 260, ypos[15]+17);
  404.       Text(rp, "Green", 5);
  405.       for(i=0; i<16; i++)
  406.       {
  407.          Move(rp, xpos[i]+3, ypos[15]+17);
  408.          Text(rp, number[i], 1);
  409.       }
  410.  
  411.       SetAPen(rp, 3);              /* Blue pen for blue color numbers   */
  412.       Move(rp, 4, 18);
  413.       Text(rp, "Blue", 4);
  414.       for(i=0; i<16; i++)
  415.       {
  416.          Move(rp, 7, ypos[i]+6);
  417.          Text(rp, number[i], 1);
  418.       }
  419.  
  420.       SetAPen(rp, 1);              /* Red pen for red color numbers     */
  421.       Move(rp, 271, 100);
  422.       Text(rp, "Red", 3);
  423.  
  424.       sequence = 0;
  425.    }
  426.  
  427.    SetAPen(rp, 1);                 /* Identify the red color in use     */
  428.    SetDrMd(rp, JAM2);
  429.    Move(rp, 280, 115);
  430.    Text(rp, number[sequence], 1);
  431.  
  432.    for(j=0; j<16; j++)             /* Update all of the squares         */
  433.       for(i=0; i<16; i++)
  434.          hamBox((sequence<<8 | i<<4 | j), xpos[i], ypos[j]);
  435.  
  436.    if(++sequence == 16) sequence=0;
  437. }
  438.  
  439.  
  440. prompt()                           /* Display mode changing prompt */
  441. {
  442.    SetDrMd(rp, JAM2);
  443.    SetAPen(rp, 4);
  444.    Move(rp, 23, 183);
  445.    Text(rp, "[left mouse button = new mode]", 30);
  446.    textneeded = FALSE;
  447. }
  448.  
  449.  
  450. /**********************************************************************
  451.  *  hamBox() -- routine to draw a colored box in Hold and Modify mode.
  452.  *              Draws a box of size XSIZE by YSIZE with an upper left
  453.  *              corner at (x,y).  The desired color is achieved in 3
  454.  *              steps on each horizontal line of the box.  First we
  455.  *              set the red component, then the green, then the blue.
  456.  *              We achieve this by drawing a vertical line of Modify-Red,
  457.  *              followed by a vertical line of Modify-Green, followed by
  458.  *              a rectangle of Modify-Blue.  Note that the resulting
  459.  *              color for the first two vertical lines depends upon the
  460.  *              color(s) of the pixels immediately to the left of that
  461.  *              line.  By the time we reach the rectangle we are assured
  462.  *              of getting (and maintaining) the desired color because
  463.  *              we have set all 3 components (R, G, and B) straight from
  464.  *              the bit map.
  465.  ***********************************************************************/
  466. hamBox(color, x, y)
  467. LONG   color, x, y;
  468. {
  469.    SHORT  c;
  470.  
  471.    SetDrMd(rp, JAM1);      /* Establish Drawing Mode in RastPort       */
  472.  
  473.    c=((color & 0xf00)>>8); /* Extract desired Red color component.     */
  474.    SetAPen(rp, c + 0x20);  /* Hold G, B from previous pixel.  Set R=n. */
  475.    Move(rp, x, y);
  476.    Draw(rp, x, y+YSIZE);
  477.  
  478.    x++;
  479.    c=((color & 0xf0)>>4);  /* Extract desired Green color component.   */
  480.    SetAPen(rp, c + 0x30);  /* Hold R, B from previous pixel.  Set G=n. */
  481.    Move(rp, x, y);
  482.    Draw(rp, x, y+YSIZE);
  483.  
  484.    x++;
  485.    c=(color & 0xf);        /* Extract desired Blue color component.    */
  486.    SetAPen(rp, c + 0x10);  /* Hold R, G from previous pixel.  Set B=n. */
  487.    RectFill(rp, x, y, x+XSIZE-2, y+YSIZE);
  488. }
  489.  
  490.